﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LiveSequence;
using LiveSequence.Common.Domain;
using LiveSequence.Common.Tree;
using LiveSequence.Suite.Controllers;
using LiveSequence.Suite.Documents;
using LiveSequence.Suite.Domain;
using LiveSequence.Suite.Interfaces;

using LiveSequence.Suite.Views;
using LiveSequence.Suite.Interfaces;
using DataTreeLib;
using System.Diagnostics;
using LiveSequence.Suite.Dialogs;
using LiveSequence.Suite.Utils;

namespace LiveSequence.Suite.Views
{
  public partial class MethodCallTreeView : BaseView<SeqDiagramDoc>
  {
    private DTreeNode<object> _root;
    private TreeViewController<object> _treeViewController;
    private DocManager _docManager;

    public MethodCallTreeView()
    {
      InitializeComponent();
      InitializeComponentEx();
      _docManager = DocManager.Instance;

      _treeViewController = new TreeViewController<object>(_methodCallTreeView,
                              _root,
                              new MethodCallTreeNodeMapper(this));
      
      SelectedDocumentChanged += new EventHandler(MethodCallTreeView_SelectedDocumentChanged);
      _docManager.ActiveDocumentChanged += new EventHandler(_docManager_ActiveDocumentChanged);
      if(_docManager.ActiveDocument is SeqDiagramDoc)
      {
        SelectedDocument = _docManager.ActiveDocument as SeqDiagramDoc;
      }

      Enabled = false;
    }

    private void InitializeComponentEx()
    {
      _methodCallTreeView.CheckBoxes = true;
      _searchingTreeViewController = new SearchingTreeViewController(_methodCallTreeView, _searchingToolStrip);
      _searchingTreeViewController.SearchText += new EventHandler(_searchingTreeViewController_SearchText);
    }

    void MethodCallTreeView_SelectedDocumentChanged(object sender, EventArgs e)
    {
      this.Enabled = (SelectedDocument != null);
      if(SelectedDocument != null)
      {
        LSMethodCallDiagram diagram = SelectedDocument.Diagram;
        createMethodCallTree(diagram.SequenceData);
        _treeViewController.Data = _root;

        UpdateView();
      }

    }

    void _docManager_ActiveDocumentChanged(object sender, EventArgs e)
    {
      SeqDiagramDoc document = _docManager.ActiveDocument as SeqDiagramDoc;
      if(document != null)
      {
        SelectedDocument = document;
      }
    }

    private SearchingTreeViewController _searchingTreeViewController;


    void _searchingTreeViewController_SearchText(object sender, EventArgs e)
    {
      string searchedText = _searchingTreeViewController.SearchedText;
      TreeNode tNode = TreeViewHelper.SearchTreeNode(_methodCallTreeView, new TextTNodeComparer(searchedText));
      if (tNode != null)
      {
        tNode.EnsureVisible();
        _methodCallTreeView.SelectedNode = tNode;
      }

    }

    void _methodCalltreeView_AfterSelect(object sender, TreeViewEventArgs e)
    {
      DTreeNode<object> methodNode = e.Node.Tag as DTreeNode<object>;
      if (methodNode != null)
      {
        PropertyViewManager.Instance.SetObject(this.SelectedDocument, methodNode.Value);
      }
    }

    void _methodCalltreeView_AfterCheck(object sender, TreeViewEventArgs e)
    {
      if((e.Action == TreeViewAction.ByKeyboard) || (e.Action == TreeViewAction.ByMouse))
      {
        DTreeNode<object> dTreeNode = _treeViewController.GetDataNode(e.Node);
        MethodCallInfo methodCallInfo = dTreeNode.Value as MethodCallInfo;
        if (methodCallInfo != null)
        {
          methodCallInfo.Visible = e.Node.Checked;
        }

        UpdateDoc();
 
        _treeViewController.UpdateNode(e.Node, false);
        
      }
      _tslblVisibleNodes.Text = string.Format("{0} Visible Nodes",countVisibleTreeNodes(_root));
    }

    private void UpdateDoc()
    {
      _document.OnUpdateAllViews(this, null);
    }

    private void CheckChildTreeNodes(TreeNode treeNode, bool bChecked)
    {
      foreach (TreeNode child in treeNode.Nodes)
      {
        DTreeNode<object> dTreeNode = _treeViewController.GetDataNode(child);
        MethodCallInfo methodCallInfo = dTreeNode.Value as MethodCallInfo;
        Debug.Assert(methodCallInfo!=null);
        methodCallInfo.Visible = bChecked;
        child.Checked = bChecked;
        CheckChildTreeNodes(child, bChecked);
      }

    }

    int countVisibleTreeNodes(DTreeNode<object> dNode)
    {
      int iCount = 0;
      MethodCallInfo methodCallInfo = dNode.Value as MethodCallInfo;
      if (methodCallInfo != null)
      {
        iCount = (methodCallInfo.Visible) ? 1 : 0;
      }

      foreach(DTreeNode<object> child in dNode.Nodes)
      {
        iCount += countVisibleTreeNodes(child);
      }
      return iCount;
    }


    void _projectController_SelectedDiagramChanged(object sender, EventArgs e)
    {
      UpdateView();
    }

    private void UpdateView()
    {
       _treeViewController.UpdateAllNodes();
      _tslblVisibleNodes.Text = string.Format("{0} Visible Nodes", countVisibleTreeNodes(_root));
    }

    private void createMethodCallTree(SequenceData data)
    {
      _root = new DTreeNode<object>("Method");

      Queue<MethodCallInfo> queueMethods = new Queue<MethodCallInfo>(data.GetMethodList());
      if (queueMethods.Count > 0)
      {
        MethodCallInfo methodCallInfo = queueMethods.Peek();

        createMethodCallSubTree(methodCallInfo.MethodName,
                                        methodCallInfo.TypeName,
                                        _root,                                       
                                        queueMethods);
      }
    }



    private void createMethodCallSubTree(string strMethodCall,
                                                 string strTypeCall,
                                                 DTreeNode<object> nodeCaller,
                                                 Queue<MethodCallInfo> queueMethods)
    {
      while (queueMethods.Count > 0)
      {
        MethodCallInfo methodCallInfo = queueMethods.Peek();

        if ((methodCallInfo.MethodName == strMethodCall) &&
          (methodCallInfo.TypeName == strTypeCall))
        {
          DTreeNode<object> child = new DTreeNode<object>(methodCallInfo);
          nodeCaller.Nodes.Add(child);
          queueMethods.Dequeue();
          createMethodCallSubTree(methodCallInfo.MethodCallName,
                                          methodCallInfo.MethodCallType,
                                          child,
                                          queueMethods);

        }
        else
        {
          break;
        }
      }

    }

    private void _tsbtnCheckAll_Click(object sender, EventArgs e)
    {
      if(_methodCallTreeView.SelectedNode != null)
      {
        CheckChildTreeNodes(_methodCallTreeView.SelectedNode, true);
        SelectedDocument.OnUpdateAllViews(this, null);
      }
    }

    private void _tsbtnUnCheckAll_Click(object sender, EventArgs e)
    {
      if (_methodCallTreeView.SelectedNode != null)
      {
        CheckChildTreeNodes(_methodCallTreeView.SelectedNode, false);
        SelectedDocument.OnUpdateAllViews(this, null);
      }
    }

    private void _tsbtnFilter_Click(object sender, EventArgs e)
    {
      LSMethodCallDiagram diagram = SelectedDocument.Diagram;
      DlgFilterMethodCallTree dlg = new DlgFilterMethodCallTree(diagram.SequenceData);
      dlg.ShowDialog();
      _treeViewController.UpdateAllNodes();
    }

    private void _tsbtnNextCheckedTNode_Click(object sender, EventArgs e)
    {
      TreeNode tNode = TreeViewHelper.SearchTreeNode(_methodCallTreeView, new CheckedTNodeComparer());
      if(tNode!=null)
      {
        tNode.EnsureVisible();
        _methodCallTreeView.SelectedNode = tNode;
      }
    }

    #region Overrides
    public override void UpdateView(object obj)
    {
      UpdateView();
    }
    #endregion


  }
}
